#include <SFML/Graphics.hpp>
#include "my_utilities/mymath.h"
#include "include/CQuadTree.h"
#include "my_utilities/CPolygon.h"
#include "my_utilities/Collision.h"
#include "my_utilities/CRigidBody.h"
#include "my_utilities/MiscHelper.h"

#include <vector>
#include <iostream>
using namespace std;

vector<CRigidBody*> body;
sf::View camera(sf::FloatRect(200, 200, 1000, 900));

CQuadTree qtree(CRect(Vec2f(-1000.0f, -1000.0f), Vec2f(1500.0f, 1500.0f)), 1);

void HandleInput(const sf::RenderWindow& App)
{
    const sf::Input& Input = App.GetInput();
    float speed = 0.06f;
    Vec2f vel = body[0]->GetVel();


    if (Input.IsKeyDown(sf::Key::Left))
    {
        vel.x -= speed;
        body[0]->SetVel(vel);
    }
    if (Input.IsKeyDown(sf::Key::E))
        body[0]->IncAngVel(.01);
    if (Input.IsKeyDown(sf::Key::Right))
    {
        vel.x += speed;
        body[0]->SetVel(vel);
    }
    if (Input.IsKeyDown(sf::Key::Up))
    {
        vel.y -= speed;
        body[0]->SetVel(vel);
    }
    if (Input.IsKeyDown(sf::Key::Down))
    {
        vel.y += speed;
        body[0]->SetVel(vel);
    }
    
    body[0]->SetVel(vel);
}

void Update()
{
    unsigned int i, j;
    for (i = 0; i < body.size(); ++i)
    {
        body[i]->Update();
    }

    vector<CQuadTreePosItem*> potentialColliders;
    unsigned int t = 0;
    for (i = 0; i < body.size(); ++i)
    {
        qtree.QueryItems(body[i]->GetBoundingRect(), potentialColliders);

        for (j = 0; j < potentialColliders.size(); ++j)
        {
            if (body[i] != potentialColliders[j]->GetParent())
            {
                TCollisionReport report(body[i], potentialColliders[j]->GetParent());
                ++t;
                if(report.collisionReported)
                    report.ApplyResponse(1.3f, 0.9f);
            }
        }
        //cout << potentialColliders.size() << endl;

        potentialColliders.clear();
    }
    //cout << t << endl;




//    for(i = 0; i < body.size(); ++i)
//	{
//		for(j = i+1; j < body.size(); ++j)
//		{
////		    if (!CircleCollision(body[i], body[j]))
////                continue;
//			TCollisionReport report(body[i], body[j]);
//
//			if(report.collisionReported)
//			{
//				report.ApplyResponse(0.3f, 0.9f);
//			}
//
//		}
//	}
}
void Render(sf::RenderWindow& App)
{
    sf::Shape poly;
    CPolygon tempP;

    App.Clear(sf::Color(50,50,128));
    qtree.Render(App);
    for (unsigned int i = 0; i < body.size(); ++i)
    {
        poly = CPolyToSFPoly(body[i]->GetPolygon());

        if (poly.GetPointPosition(0).x > -50 && poly.GetPointPosition(0).x < 1000 && poly.GetPointPosition(0).y > -50 && poly.GetPointPosition(0).y < 1000)
            App.Draw(poly);
    }



    App.Display();

}

void Cleanup()
{
    miscH::FreeClear(body);
}

int main()
{
    sf::RenderWindow App(sf::VideoMode(800, 700, 32), "SFML Window");
    App.SetFramerateLimit(60);
    sf::Event Event;

    CPolygon tempP;//(4, 40);
    CPolygon tempP2(5, 60);
    tempP.PushPoint(Vec2f(50, 0));
    tempP.PushPoint(Vec2f(100, 50));
    tempP.PushPoint(Vec2f(50, 160));
    tempP.PushPoint(Vec2f(0, 50));
    tempP.BuildPolygon();


    tempP2 = CPolygon(4, 7);
    body.push_back(new CRigidBody(Vec2f(50, 180), tempP2));
    body.push_back(new CRigidBody(Vec2f(50, 200), tempP2));



    for (unsigned int i = 0; i < 20; ++i)
    {
        for (unsigned int j = 0; j < 8; ++j)
        {
            tempP2 = CPolygon(4, 7);
            body.push_back(new CRigidBody(Vec2f(200+i*33, 200+j*33), tempP2));
        }
    }

    for (unsigned int i = 0; i < body.size(); ++i)
        qtree.Insert(&body[i]->qt_);


    while (App.IsOpened())
    {
        while (App.GetEvent(Event))
        {
            if (Event.Type == sf::Event::Closed)
            {
                App.Close();
            }
            if (Event.Type == sf::Event::MouseWheelMoved)
            {
                float delta = (float)Event.MouseWheel.Delta;

                if (delta > 0)
                    camera.Zoom(1.03f);
                else if (delta < 0)
                    camera.Zoom(0.96f);
            }
            
            if ((Event.Type == sf::Event::MouseButtonPressed) && (Event.MouseButton.Button == sf::Mouse.Button.Left))
            {
                vector<CQuadTreePosItem*> items;
                qtree.DebugQueryItems(new Vec2f(Event.MouseMove.X, Event.MouseMove.Y), items);
                cout << items.size() << endl;
            }
        }

        Vec2f cameraPos;
        cameraPos = body[0]->GetPos();
        camera.SetCenter(cameraPos.x, cameraPos.y);
        App.SetView(camera);

        HandleInput(App);
        Update();
        Render(App);

        //cout << 1.0 / App.GetFrameTime() << endl;

    }

    Cleanup();

    return EXIT_SUCCESS;
}
